import 'package:bruno/bruno.dart';
import 'package:dart_date/dart_date.dart';
import 'package:flutter/material.dart';
import 'package:reactive_forms/reactive_forms.dart';

typedef YtReactiveDatePickerBuilder<T> = Widget Function(BuildContext context,
    YtReactiveDatePickerDelegate<T> picker, Widget? child);

class ReactiveBrunoDatePicker<T> extends ReactiveFormField<T, DateTime> {
  ReactiveBrunoDatePicker({
    Key? key,
    String? formControlName,
    FormControl<T>? formControl,
    required YtReactiveDatePickerBuilder<T> builder,
    Widget? child,
    bool rootNavigator = false,
    bool? canBarrierDismissible,
    DateTime? minDateTime,
    DateTime? maxDateTime,
    DateTime? initialDateTime,
    String dateFormat = 'yyyy-MM-dd',
    int minuteDivider = 1,
    BrnDateTimePickerMode pickerMode = BrnDateTimePickerMode.date,
    BrnPickerTitleConfig pickerTitleConfig = BrnPickerTitleConfig.Default,
    dynamic Function()? onCancel,
    dynamic Function()? onClose,
    dynamic Function(DateTime, List<int>)? onChange,
    dynamic Function(DateTime, List<int>)? onConfirm,
  }) : super(
          key: key,
          formControl: formControl,
          formControlName: formControlName,
          builder: (ReactiveFormFieldState<T, DateTime> field) {
            return builder(
              field.context,
              YtReactiveDatePickerDelegate<T>._(
                field,
                (field) => BrnDatePicker.showDatePicker(field.context,
                    rootNavigator: rootNavigator,
                    canBarrierDismissible: canBarrierDismissible,
                    minDateTime: minDateTime,
                    maxDateTime: maxDateTime,
                    initialDateTime: initialDateTime,
                    dateFormat: dateFormat,
                    minuteDivider: minuteDivider,
                    pickerMode: pickerMode,
                    pickerTitleConfig: pickerTitleConfig,
                    onCancel: onCancel,
                    onClose: onClose,
                    onChange: onChange, onConfirm: (dateTime, selectedIndex) {
                  field.didChange(dateTime);
                  onConfirm?.call(dateTime, selectedIndex);
                }),
              ),
              child,
            );
          },
        );

  @override
  ReactiveFormFieldState<T, DateTime> createState() =>
      _YtReactiveDatePickerState<T>();
}

/// Definition of the function responsible for show the date picker.
typedef _YtShowDatePickerCallback<T> = void Function(
    ReactiveFormFieldState<T?, DateTime> field);

/// This class is responsible of showing the picker dialog.
///
/// See also [ReactiveDatePicker].
class YtReactiveDatePickerDelegate<T> {
  final ReactiveFormFieldState<T, DateTime> _field;
  final _YtShowDatePickerCallback<T> _showPickerCallback;

  YtReactiveDatePickerDelegate._(this._field, this._showPickerCallback);

  /// Gets the control bound to the [ReactiveTimePicker] widget
  FormControl<T> get control => _field.control;

  /// Gets the value selected in the date picker.
  DateTime? get value => _field.value;

  /// Shows the time picker dialog.
  void showPicker() {
    _showPickerCallback(_field);
  }
}

class _YtReactiveDatePickerState<T>
    extends ReactiveFormFieldState<T, DateTime> {
  @override
  ControlValueAccessor<T, DateTime> selectValueAccessor() {
    if (control is FormControl<String>) {
      return Iso8601DateTimeValueAccessor()
          as ControlValueAccessor<T, DateTime>;
    } else if (control is FormControl<DateTime>) {
      return super.selectValueAccessor();
    }

    throw ValueAccessorException('Invalid widget binding. ReactiveDatePicker '
        'widget must be bound to a control that inherited from '
        'AbstractControl<String> or AbstractControl<DateTime>. '
        'Control of type: ${control.runtimeType} is not valid.');
  }
}
